package com.tzq.autoticket;

import com.tzq.autoticket.bean.Tourist;
import com.tzq.autoticket.utils.Log;
import com.tzq.autoticket.utils.TUtils;
import com.tzq.autoticket.utils.WebUtils;
import com.tzq.autoticket.utils.XlsUtils;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static final boolean DEBUG = false;
    private static final int STATE_INIT = -1;
    private static final int STATE_OK = 0;
    private static final int STATE_NEED_RELOGIN = 1;
    private static final int STATE_NO_MUCH_TICKET = 2;
    private static final int STATE_FAIL = 3;
    static int state = STATE_INIT;

    public static void main(String[] args) {
        System.setProperty("webdriver.chrome.driver", Config.getDriverPath());
        ChromeDriver driver = new ChromeDriver();
        try {
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.info("---------shutdown");
                    try {
                        driver.close();
                    } catch (Exception e) {

                    }
                }
            }));
            while (true) {
                boolean reLoad = false, reLogin = false;
                if (state == STATE_INIT) {
                    reLoad = true;
                    reLogin = true;
                } else if (state == STATE_OK) {
                    reLoad = true;
                    reLogin = false;
                } else if (state == STATE_NEED_RELOGIN) {
                    reLoad = false;
                    reLogin = true;
                } else if (state == STATE_NO_MUCH_TICKET) {
                    reLoad = false;
                    reLogin = false;
                }
                if (auto(driver, reLoad, reLogin)) {
                    if (Config.getInstance().getTouristList().isEmpty()) {
                        Log.info("已全部买到票了，程序准备退出。。。。");
                        break;
                    } else {
                        Log.info("3秒后继续刷票");
                        Thread.sleep(3000);
                    }
                } else {
                    if (state == STATE_NEED_RELOGIN) {
                        Log.err("需要重新登录!");
                    } else if (state == STATE_NO_MUCH_TICKET) {
                        Log.err("余票库存不足，继续刷票！");
                    } else {
                        Log.err("刷票失败，程序准备退出。。。。");
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (DEBUG) {
                try {
                    Thread.sleep(1000000000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            driver.close();
        }
    }

    private static void login(WebDriver driver) throws Exception {
        WebUtils.getUserName(driver).sendKeys(Config.getInstance().getUserName());
        driver.findElement(By.id("password")).sendKeys(Config.getInstance().getPassword());
        final WebElement vCodeElement = driver.findElement(By.id("random"));
        vCodeElement.clear();
        Log.info("请输入验证码...");
        new WebDriverWait(driver, 100).until(webDriver -> {
            String value = vCodeElement.getAttribute("value");
            if (value != null && value.length() == 4) {
                return vCodeElement;
            } else {
                return null;
            }
        });
        Log.info("登录...");
        driver.findElement(By.id("loginSubmit")).click();
    }


    private static void CheckState(WebDriver driver) throws Exception {
        state = STATE_OK;
        Object locker = new Object();
        Log.info("检查当前状态...");
        ElementWaiter uploadWaiter = new ElementWaiter() {
            @Override
            WebElement get() {
                return driver.findElement(By.id("teamFile"));
            }
        };

        ElementWaiter reloadWaiter = new ElementWaiter() {
            @Override
            WebElement get() {
                return driver.findElement(By.partialLinkText("[立即登录]"));
            }
        };

        ElementWaiter noMuchWaiter = new ElementWaiter() {
            @Override
            WebElement get() {
                return driver.findElement(By.partialLinkText("九寨沟门票预订数量大于剩余库存数量"));
            }
        };

        new Thread(() -> {
            WebElement uploadE = uploadWaiter.waitElement();
            if (uploadE != null) {
                state = STATE_OK;
                synchronized (locker) {
                    locker.notify();
                }
            }
        }).start();

        new Thread(() -> {
            WebElement element = reloadWaiter.waitElement();
            if (element != null) {
                state = 2;
                element.click();
                synchronized (locker) {
                    locker.notify();
                }
            }
        }).start();

        new Thread(() -> {
            WebElement element = noMuchWaiter.waitElement();
            if (element != null) {
                state = 3;
                element.click();
                synchronized (locker) {
                    locker.notify();
                }
            }
        }).start();

        synchronized (locker) {
            locker.wait();
        }
        Log.info("状态=" + state);
        uploadWaiter.stop();
        reloadWaiter.stop();
        noMuchWaiter.stop();
    }

    private static boolean auto(WebDriver driver, boolean needReload, boolean needLogin) throws Exception {
        if (needReload) {
            driver.get("http://b.jowong.com/provider/ticket/index.do");
        }
        if (needLogin) {
            login(driver);
        }

        new WebDriverWait(driver, 100).until(webDriver -> {
            if (driver.getPageSource().contains("订票流程")) {
                return "";
            } else {
                return null;
            }
        });

        WebElement refreshElement = WebUtils.waitRefreshbtn(driver);
//            new WebDriverWait(driver, 100).until(ExpectedConditions.visibilityOf(refreshElement));
        Log.info("刷新 " + Config.getInstance().getsDate() + " 余票...");
        refreshElement.click();
        int year = WebUtils.getYear(driver);
        int month = WebUtils.getMonth(driver);
//        Log.info("year=" + year + "  month=" + month);
        int yupiao = 0;
        WebElement yupiaoE = null;

        while (yupiao == 0) {
            while (Config.getInstance().getCalendar().get(Calendar.MONTH) > month) {
                WebElement nextMonth = driver.findElement(By.xpath("//div[@id='ui-datepicker-div']")).findElement(By.partialLinkText("下月>"));
                Log.info("点击下一月...");
                nextMonth.click();
                Thread.sleep(1000);
                month = WebUtils.getMonth(driver);
                Log.info("month=" + month);
            }

            WebElement dayE = WebUtils.waitDayComeIn(driver);
            yupiaoE = WebUtils.waitYuPiaoElement(driver, dayE);
            Log.info(yupiaoE.getText());
            Pattern pattern = Pattern.compile("余(\\d+)人");
            Matcher matcher = pattern.matcher(yupiaoE.getText());
            if (matcher.matches()) {
                yupiao = Integer.valueOf(matcher.group(1));
                Log.info("余票：" + yupiao);
            } else {
                Thread.sleep(Config.getInstance().getSleep());
                Log.info("刷新 " + Config.getInstance().getsDate() + " 余票...");
                refreshElement.click();
            }
        }
        new WebDriverWait(driver, 100).until(ExpectedConditions.elementToBeClickable(yupiaoE));
        Log.info("点击余票...");
        yupiaoE.click();


        int removeCount = Config.getInstance().getTouristList().size();
        if (removeCount > yupiao) {
            removeCount = yupiao;
        }

        List<Tourist> list = new ArrayList<>();
        for (int i = 0; i < removeCount; i++) {
            list.add(Config.getInstance().getTouristList().get(i));
        }

        CheckState(driver);
        if (state != STATE_OK) {
            return false;
        }
        WebElement uploadE = WebUtils.getUploadElement(driver);
        String nowXlsPath = TUtils.getProjectDirPath() + File.separator + "now.xls";
        XlsUtils.writeTourist(list, nowXlsPath);
        uploadE.sendKeys(nowXlsPath);
        Alert alert = WebUtils.waitAlert(driver);
        String alertText = alert.getText();
        alert.accept();
        if (alertText.contains("保存成功")) {
            Log.info("点击确定...");
            driver.findElement(By.xpath("//div[@id='submitInfo']/img")).click();
            Log.info("下一步...");
            WebUtils.waitNextButton(driver).click();
            Log.info("填写领票人信息...");
            WebUtils.waitLinpiaoren(driver).sendKeys(list.get(0).getName());
            driver.findElement(By.xpath("//input[@name='06001orhm']")).sendKeys(list.get(0).getCardNo());
            driver.findElement(By.xpath("//input[@name='06001orph']")).sendKeys(list.get(0).getPhoneNumber());
            Log.info("填写订单信息...");
            driver.findElement(By.id("dxnumber")).sendKeys(Config.getInstance().getDxNumber());
            new Select(driver.findElement(By.id("couid"))).selectByVisibleText(Config.getInstance().getDxCountry());
            new Select(driver.findElement(By.id("prvcode"))).selectByVisibleText(Config.getInstance().getDxProvince());
            Log.info("下一步...");
            driver.findElement(By.id("submitButton")).findElement(By.tagName("input")).click();
            Log.info("检测是否验证成功...");
            WebUtils.waitCheckOk(driver);
            WebElement nextBt = WebUtils.waitNextBt(driver);
            new WebDriverWait(driver, 100).until(ExpectedConditions.elementToBeClickable(nextBt));
            nextBt.click();
            Log.info("检测是否抢票成功...");
            WebUtils.waitPayDone(driver);
            Config.getInstance().getTouristSuccessList().addAll(list);
            File file = new File(Config.getInstance().getSuccessXlsPath());
            if (file.exists()) {
                file.delete();
            }
            XlsUtils.writeTourist(Config.getInstance().getTouristSuccessList(), Config.getInstance().getSuccessXlsPath());

            new Thread() {
                @Override
                public void run() {
                    int count = 0;
                    while (count < 2) {
                        try {
                            new Player(new BufferedInputStream(new FileInputStream(Config.getInstance().getSuccessAudioPath()))).play();
                        } catch (JavaLayerException e) {
                            e.printStackTrace();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                        count++;
                    }

                }
            }.start();
            return true;
        } else {
            Log.err("上传失败：" + alertText);
            state = STATE_FAIL;
            return false;
        }
    }
}
